package Simulateur;

import java.util.ArrayList;
import java.util.List;

import Controleur.GestionnaireSimulateur;
import Domaine.Noeud;
import Domaine.Reseau;
import Domaine.Urgence;
import Domaine.Urgence.EtatUrgence;
import Domaine.VehiculeUrgence;
import Domaine.VehiculeUrgence.EtatVehicule;

public class Simulation 
{
	
	public enum EtatSimulation {
		EnAttente,
		EnCours,
		Terminee
	}
	
	private Strategie _strategie;
	private StrategieAttente _strategieAttente;
	private List<Statistique> _listeStatistiques;
	public GestionnaireSimulateur _unnamed_GestionnaireSimulation_;
	public StrategieAttente _unnamed_StrategieAttente__abstract__;
	public Strategie _unnamed_Strategie_;
	public Statistique _unnamed_Statistique_;
	private Reseau _reseau;
	private boolean _logStats = false;
	private Noeud _noeudSuivant;
	
	private EtatSimulation _etat;
	
	public EtatSimulation getEtat() {
		return _etat;
	}
	
	public void setEtat(EtatSimulation etat) {
		_etat = etat;
	}
	
	public Strategie getStrategie() 
	{
		return this._strategie;
	}

	public void setStrategie(Strategie aStrategie) 
	{
		this._strategie = aStrategie;
	}

	public StrategieAttente getStrategieAttente() 
	{
		return this._strategieAttente;
	}

	public void setStrategieAttente(StrategieAttente aStrategieAttente) 
	{
		this._strategieAttente = aStrategieAttente;
	}

	public List<Statistique> getListeStatistiques() 
	{
		throw new UnsupportedOperationException();
	}

	public void setListeStatistiques(List<Statistique> aListeStatistiques) 
	{
		throw new UnsupportedOperationException();
	}

	/**
	 * @return the _listeStatistiques
	 */
	public List<Statistique> get_listeStatistiques() {
		return _listeStatistiques;
	}

	/**
	 * @param _listeStatistiques the _listeStatistiques to set
	 */
	public void set_listeStatistiques(List<Statistique> _listeStatistiques) {
		this._listeStatistiques = _listeStatistiques;
	}
	
	
	public Simulation(Reseau reseau) {
		_reseau = reseau;
		
		_strategie = new UrgencePlusAncienne(reseau);
		_strategieAttente = new RetourPortAttache(reseau);
		_listeStatistiques = new ArrayList<Statistique>();
	}
	
	
	private Domaine.Urgence _urgenceEnCours;
	private List<Noeud> _parcoursCourant;
	private Noeud _debutCourant;
	private Noeud _finCourant;
	private Noeud _noeudCourant;
	private float _distance;
	private float _distanceParcourue;
	private int _tempsTraitementUrgence = 0;
	
	
	public void traiterUrgence(Boolean interactif) {
		
		Boolean estTerminee = false;
		_etat = EtatSimulation.EnCours;
		
		while (!estTerminee || !interactif) {
			
			estTerminee = true;
			
			VehiculeUrgence vehicule = _reseau.getVehiculeUrgence();
			if (vehicule == null)
				return;
			
			if (vehicule.getEtat() == EtatVehicule.EnAttente) {
				
				this.obtenirUrgence();
				
			} else if (_urgenceEnCours != null && vehicule.getEtat() == EtatVehicule.TraitementUrgence) {
				
				_tempsTraitementUrgence++;
				
				if (_tempsTraitementUrgence >= _urgenceEnCours.getTempsTraitement()) {
					
					_urgenceEnCours.setEtat(EtatUrgence.Traitee);
					this.obtenirUrgence();
					
				}
						
				
			} else if (vehicule.getEtat() == EtatVehicule.EnDeplacement) {
				//Si le segment est complete
				if (_reseau.getSegment(_noeudCourant, _noeudSuivant) != null) 
				{
					//Faire avancer le vehicule
					int deplacement = (int) vehicule.getVitesse();
					_distanceParcourue += deplacement;
					_reseau.getVehiculeUrgence().setCoordonnee(
							Noeud.obtenirCoordonneeDistance(_reseau.getVehiculeUrgence().getCoordonnee(), _noeudSuivant, _reseau.getVehiculeUrgence().getVitesse()));
				}
				
				if (_distanceParcourue >= _distance) {
					if (_reseau.getSegment(_noeudCourant, _noeudSuivant) == null) 
					{
						vehicule.setEtat(EtatVehicule.EnAttente);
					}
					else
					{
						//Traiter prochain segment
						if (_reseau.getSegment(_noeudCourant, _noeudSuivant) != null) 
						{
							_reseau.getVehiculeUrgence().setDistanceParcourue(_reseau.getVehiculeUrgence().getDistanceParcourue()+_distance);
							_reseau.getVehiculeUrgence().setCoordonnee(_noeudSuivant.getCoordonee());
						}
						
						_distanceParcourue = 0;
						Noeud noeud = obtenirProchainNoeud();
						
						if (noeud != null) {
							Domaine.Segment segment = _reseau.getSegment(_noeudSuivant, noeud);
							_noeudCourant = _noeudSuivant;
							_noeudSuivant = noeud;
							
							_distance = segment.get_longueur();
						
						} else {
							//Si arriver a l'urgence
							_noeudCourant = _finCourant;
							//vehicule.setCoordonnee(_noeudCourant.getCoordonee());
							
							if (_urgenceEnCours != null) {
								vehicule.setEtat(EtatVehicule.TraitementUrgence);
							} else {
								vehicule.setEtat(EtatVehicule.EnAttente);
							}
						
						}
					}
					
				}
			}	
		}
	}
	
	
	private void obtenirUrgence() {
		
		VehiculeUrgence vehicule = _reseau.getVehiculeUrgence();
		
		
		//Obtenir prochain urgence
		Simulateur.Strategie strategie = this.getStrategie();
		_urgenceEnCours = strategie.obtenirProchainUrgence();
		
		if (_urgenceEnCours == null) {
			
			if (_logStats) {
				Statistique stat = new Statistique(this, _reseau);
				_listeStatistiques.add(stat);
				_logStats = false;
			}
			//Retour au port d atache ou reste sur place
			StrategieAttente attente = this.getStrategieAttente();
			
			if (_noeudCourant == null)
				_noeudCourant = vehicule.getPortAttache();
			
			_parcoursCourant = attente.obtenirParcourRetour(_noeudCourant);
			
			if (_parcoursCourant == null) {
				vehicule.setEtat(EtatVehicule.EnAttente);
			} else {
				vehicule.setEtat(EtatVehicule.EnDeplacement);
			}
		} else {
			
			_logStats = true;
			
			if (_noeudCourant == null)
				_noeudCourant = vehicule.getPortAttache();
			
			Noeud noeudUrgence = null;
			List<Urgence> lstUrgence;
			
			for (Noeud noeudURG : _reseau.getListeNoeuds())
			{
				lstUrgence = noeudURG.getListeUrgences();
				for (Urgence urgenceNoeud : lstUrgence)
				{
					if (urgenceNoeud == _urgenceEnCours)
					{
						noeudUrgence = noeudURG;
					}
				}
			}
			_parcoursCourant = _reseau.obtenirCheminPlusCourt(_noeudCourant, noeudUrgence);
			
			//_parcoursCourant = _reseau.obtenirCheminPlusCourt(_noeudCourant, _urgenceEnCours.getNoeud());
			_tempsTraitementUrgence = 0;
			
			
			vehicule.setEtat(EtatVehicule.EnDeplacement);
		}
			
		if (vehicule.getEtat() == EtatVehicule.EnDeplacement) {
			_debutCourant = _parcoursCourant.get(0);
			_noeudCourant = _debutCourant;
			_finCourant = _parcoursCourant.get(_parcoursCourant.size()-1);
			
			_noeudSuivant = _parcoursCourant.size() > 1 ? _parcoursCourant.get(1) : _debutCourant;
			
			Domaine.Segment segment = _reseau.getSegment(_noeudCourant, _noeudSuivant);
			
			_distanceParcourue = 0;
			_distance = _debutCourant == _finCourant ? 0 : segment.get_longueur();
		}
	}
	
	private Noeud obtenirProchainNoeud() {
		
		for (int i = 0; i < _parcoursCourant.size() - 1; i++) {
			if (_noeudSuivant == _parcoursCourant.get(i)) 
			{
				return _parcoursCourant.get(i+1);
			}
		}
		
		return null;
	}
	
}